import {
  Body,
  Controller,
  Delete,
  Get,
  Logger,
  Param,
  ParseArrayPipe,
  Post,
  Put,
  Query,
} from '@nestjs/common';
import {
  ApiOperation,
  ApiParam,
  ApiTags,
  ApiExcludeEndpoint,
  ApiBearerAuth,
  ApiExcludeController,
} from '@nestjs/swagger';

import { ApiResult } from '~/common/decorators/api-result.decorator';
import { IdParam } from '~/common/decorators/id-param.decorator';
import { MenuService } from '~/modules/system/menu/menu.service';

import { Perm, definePermission } from '../auth/decorators/permission.decorator';

import { UserPasswordDto } from './dto/password.dto';
import { UserDto, UserNormalQueryDto, UserQueryDto, UserUpdateDto } from './dto/user.dto';
import { UserEntity } from './user.entity';
import { UserService } from './user.service';
import { Public } from '../auth/decorators/public.decorator';
import { AllowAnon } from '../auth/decorators/allow-anon.decorator';
import { AuthUser } from '../auth/decorators/auth-user.decorator';
import { ModuleSwaggerTags } from '~/constants/modules.constant';
import { IUserInfoModel } from './user.model';

export const permissions = definePermission('system:user', {
  LIST: 'list',
  CREATE: 'create',
  READ: 'read',
  UPDATE: 'update',
  DELETE: 'delete',
  PASSWORD_UPDATE: 'password:update',
  PASSWORD_RESET: 'pass:reset',
} as const);

@ApiTags(ModuleSwaggerTags.USER)
@ApiBearerAuth()
@Controller('cms/user')
export class UserController {
  private readonly logger = new Logger(UserController.name);

  constructor(private userService: UserService, private menuService: MenuService) {
    this.logger.log('UserController', permissions);
  }

  @ApiExcludeEndpoint()
  @Get('list')
  @ApiOperation({ summary: '获取用户列表' })
  @ApiResult({ type: [UserEntity], isPage: true })
  @Perm(permissions.LIST)
  async list(@Query() dto: UserQueryDto) {
    return this.userService.list(dto);
  }

	@Get('list/normal')
	@ApiOperation({ summary: '获取普通用户列表' })
	@ApiResult({ type: [UserEntity], isPage: true })
	async listUserNormal(@Query() dto: UserNormalQueryDto) {
		return this.userService.listUserNormal(dto);
	}

	@Get('listByTenant')
	@ApiOperation({ summary: '获取租户用户列表' })
	@ApiResult({ type: [UserEntity], isPage: true })
	async listByTenant(@Query() dto: UserQueryDto) {
		return this.userService.listByTenant(dto);
	}

  @Get(':id')
  @ApiOperation({ summary: '查询用户详情' })
  async read(@Param('id') id: number): Promise<any> {
    return await this.userService.getAccountInfo(id);
  }

	@Get('info')
	@ApiOperation({ summary: '获取当前登录用户信息' })
	@ApiResult({ type: UserEntity })
	@AllowAnon()
	async info(@AuthUser() user: IAuthUser): Promise<Partial<IUserInfoModel>> {
		return await this.userService.getAccountInfo(user.uid);
	}

  @Public()
  @AllowAnon()
  @Post('register/admin')
  @ApiOperation({ summary: '新增管理员' })
  // @Perm(permissions.CREATE)
  async createAdmin(@Body() dto: UserDto): Promise<UserEntity> {
    // 创建管理员
    return await this.userService.createAdmin(dto);
  }

  @ApiExcludeEndpoint()
  @Put(':id')
  @ApiOperation({ summary: '更新用户' })
  @Perm(permissions.UPDATE)
  async update(@IdParam() id: number, @Body() dto: UserUpdateDto): Promise<void> {
    await this.userService.update(id, dto);
    await this.menuService.refreshPerms(id);
  }

  @ApiExcludeEndpoint()
  @Delete(':id')
  @ApiOperation({ summary: '删除用户' })
  @ApiParam({
    name: 'id',
    type: String,
    schema: { oneOf: [{ type: 'string' }, { type: 'number' }] },
  })
  @Perm(permissions.DELETE)
  async delete(
    @Param('id', new ParseArrayPipe({ items: Number, separator: ',' })) ids: number[]
  ): Promise<void> {
    await this.userService.delete(ids);
    await this.userService.multiForbidden(ids);
  }

  @ApiExcludeEndpoint()
  @Post(':id/password')
  @ApiOperation({ summary: '更改用户密码' })
  @Perm(permissions.PASSWORD_UPDATE)
  async password(@IdParam() id: number, @Body() dto: UserPasswordDto): Promise<void> {
    await this.userService.forceUpdatePassword(id, dto.password);
  }

	@Put("switch/:userId/tenant/:tenantId")
	@ApiOperation({ summary: '切换用户租户' })
	@ApiResult({ type: UserEntity })
	async switchTenant(@Param('userId') userId: number, @Param('tenantId') tenantId: number): Promise<void> {
		await this.userService.switchTenant(userId, tenantId);
	}
}
